package com.bauer.java.pdf.text.util;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.AffineTransform;
import com.itextpdf.kernel.pdf.PdfArray;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.FilteredTextEventListener;
import com.itextpdf.kernel.pdf.canvas.parser.listener.ITextExtractionStrategy;
import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy;
import com.itextpdf.layout.element.Image;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @Author ：rui.wei
 * @Date ：Created in 9:27 2019/3/29
 * @Description：
 */
public class PDFUtils {

    private static Logger logger = LoggerFactory.getLogger(PDFUtils.class);

    public static void main(String[] args) throws Exception {

        String basePath = PDFUtils.class.getResource("/").getPath();

        String srcPath = basePath + "template.pdf";
        String destPath = basePath + "out.pdf";
        String imgPath = basePath + "contract.png";
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("name", "asdfasdfasdf");

        PdfPositon pdfPositon = new PdfPositon();
        pdfPositon.setSacle(0.5f);
        pdfPositon.setPageNo(1);
        pdfPositon.setKeyWord("盖章");
        pdfPositon.setType(PositionTypeEnum.KEYWORD_POSITION.getCode());
        pdfPositon.setImgPath(imgPath);
        PdfPositon pdfPositon1 = new PdfPositon();
        pdfPositon1.setSacle(0.5f);
        pdfPositon1.setPageNo(1);
        pdfPositon1.setKeyWord("性别");
        pdfPositon1.setType(PositionTypeEnum.KEYWORD_POSITION.getCode());
        pdfPositon1.setImgPath(imgPath);

        PdfPositon pdfPositon2 = new PdfPositon();
        pdfPositon2.setPosX(100);
        pdfPositon2.setPosY(100);
        pdfPositon2.setSacle(0.5f);
        pdfPositon2.setPageNo(1);
        pdfPositon2.setKeyWord("性别");
        pdfPositon2.setType(PositionTypeEnum.XY_POSTION.getCode());
        pdfPositon2.setImgPath(imgPath);

        fillParam(srcPath, destPath, paramMap, Arrays.asList(pdfPositon, pdfPositon1,pdfPositon2));
    }


    public static void fillParam(String templatePath, String destPath, Map<String, Object> map,
            List<PdfPositon> pdfPositons) {

        try {
            PdfReader reader = new PdfReader(templatePath);
            PdfWriter pdfWriter = new PdfWriter(destPath);
            fillParam(reader, pdfWriter, map, pdfPositons);
        } catch (Exception e) {
            logger.error(templatePath, e);
        }

    }

    public static void fillParam(InputStream templateInpuSteam, OutputStream destOutputStream,
            Map<String, Object> map, List<PdfPositon> pdfPositons) {
        try {
            PdfReader reader = new PdfReader(templateInpuSteam);
            PdfWriter pdfWriter = new PdfWriter(destOutputStream);
            fillParam(reader, pdfWriter, map, pdfPositons);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void fillParam(PdfReader pdfReader, PdfWriter pdfWriter,
            Map<String, Object> map, List<PdfPositon> pdfPositons) throws Exception {

        //1、创建pdf文件
        PdfDocument pdf = new PdfDocument(pdfReader, pdfWriter);

        //2、创建中文字体
        PdfFont f2 = null;
        try {
            f2 = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", true);
        } catch (IOException e) {
            logger.error("create Font Error");
        }
        pdf.addFont(f2);

        //3、获取pdf模板中的域值信息
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
        Map<String, PdfFormField> fieldMap = form.getFormFields();
        Iterator<String> paramIterator = map.keySet().iterator();
        while (paramIterator.hasNext()) {
            String key = paramIterator.next();
            String value = map.get(key).toString();
            PdfFormField formField = fieldMap.get(key);
            if (formField == null) {
                continue;
            }

            //4、判断文本域是否超出宽度   且文本域是单行
            if (!compareWidth(f2, formField, value) && !formField.isMultiline()) {
                logger.error("value width was out of text width fieldName:{}", key);
            }

            //5、填充信息
            formField.setValue(value);
        }

        //6、设置文本不可编辑
        form.flattenFields();

        getKeyWordPosition(pdfPositons, pdf);

        //填充图片信息
        if (pdfPositons != null && pdfPositons.size() > 0) {
            addPicture(pdf, pdfPositons);
        }
        pdf.close();

    }


    /**
     * 根据关键字查询  关键字位置
     */
    private static List<PdfPositon> getKeyWordPosition(List<PdfPositon> pdfPositons, PdfDocument pdf) {

        if (pdfPositons == null && pdfPositons.size() == 0) {
            return pdfPositons;
        }

        //检索出是关键字定位的文章
        List<PdfPositon> keyWordPositions = new ArrayList<>();
        for (PdfPositon pdfPositon : pdfPositons) {
            if (PositionTypeEnum.KEYWORD_POSITION.getCode() == pdfPositon.getType()) {
                keyWordPositions.add(pdfPositon);
            }
        }

        if (keyWordPositions.isEmpty()) {
            return pdfPositons;
        }

        KeyWordIEventFilter keyWordIEventFilter = new KeyWordIEventFilter(keyWordPositions);
        ITextExtractionStrategy textExtractionStrategy = new FilteredTextEventListener(
                new LocationTextExtractionStrategy(), keyWordIEventFilter);

        for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
            keyWordIEventFilter.setPageNo(i);
            PdfTextExtractor.getTextFromPage(pdf.getPage(i), textExtractionStrategy);
        }

        return pdfPositons;
    }

    /**
     * 1、获取文本框的宽度   注意要减去左右的padding值   值为：PdfFormField.X_OFFSET 2、获取字符串宽度注意字体   需使用中文字体
     *
     * @param pdfFont 字体
     * @param formField 文本域
     * @param value 文本值
     * @return textWidth >= valueWidth return true else false
     */
    public static boolean compareWidth(PdfFont pdfFont, PdfFormField formField, String value) {
        float fontSize = getFontSize(formField);
        PdfArray position = formField.getWidgets().get(0).getRectangle();
        float width = (float) (position.getAsNumber(2).getValue() - position.getAsNumber(0).getValue())
                - PdfFormField.X_OFFSET * 2;

        //获取当前文本字体大小
        float strWidth = pdfFont.getWidth(value, fontSize);
        return width >= strWidth;
    }

    /**
     * 获取adobe中设置的字体大小
     */
    private static float getFontSize(PdfFormField formField) {

        String defaultAppearance = formField.getDefaultAppearance().toString();
        String[] daTable = defaultAppearance.split(" ");
        return Float.valueOf(daTable[PdfFormField.DA_SIZE]);

    }


    /**
     * 追加印章之类的照片
     *
     * @param pdfDocument 文件对象
     * @param pdfPositons 照片位置信息
     */
    public static void addPicture(PdfDocument pdfDocument, List<PdfPositon> pdfPositons)
            throws MalformedURLException {

        for (PdfPositon pdfPositon : pdfPositons) {
            ImageData image = ImageDataFactory.create(pdfPositon.getImgPath());
            Image imageModel = new Image(image);

            float scx = imageModel.getImageScaledWidth() * pdfPositon.getSacle();
            float scy = imageModel.getImageScaledHeight() * pdfPositon.getSacle();

            AffineTransform at = AffineTransform
                    .getTranslateInstance(pdfPositon.getPosX() - scx / 2, pdfPositon.getPosY() - scy / 2);
            at.concatenate(AffineTransform.getScaleInstance(scx, scy));

            PdfCanvas canvas = new PdfCanvas(pdfDocument.getPage(pdfPositon.getPageNo()));

            float[] matrix = new float[6];
            at.getMatrix(matrix);
            canvas.addImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4],
                    matrix[5]);
        }

    }

}
